/**
 * crawler
 *
 * outlook@China software studio
 * Copyright (c) 2008-2010. All Rights Reserved.
 * http://www.outlook.com
 */

package org.outlook.crawler.database.impl;

import java.io.File;
import java.io.UnsupportedEncodingException;

import org.outlook.crawler.database.DatabaseService;

import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

/**
 * function:
 * 
 * @author Watson email: watson.wu@hotmail.com
 * @date 2011
 */
public class JEDatabaseServiceImpl implements DatabaseService {

	private Environment databaseEnv;
	private static Database database;
	private EntryBinding dataBinding;
	private String databasePath;

	public String getDatabasePath() {
		return databasePath;
	}

	public void setDatabasePath(String databasePath) {
		this.databasePath = databasePath;
	}

	public void init() {
		try {
			EnvironmentConfig config = new EnvironmentConfig();
			config.setAllowCreate(true);
			config.setReadOnly(false);
			config.setTransactional(true);
			databaseEnv = new Environment(new File(getDatabasePath()),
					config);
			DatabaseConfig dbConfig = new DatabaseConfig();
			dbConfig.setAllowCreate(true);
			dbConfig.setTransactional(true);

			database = databaseEnv.openDatabase(null, "crawler", dbConfig);

			StoredClassCatalog classCatalog = new StoredClassCatalog(database);
			dataBinding = new SerialBinding(classCatalog, Object.class);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void destroy() {
		try {
			if (database != null) {
				database.close();
			}
			if (databaseEnv != null) {
				databaseEnv.cleanLog();
				databaseEnv.close();
			}
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}

	public Object get(Object key) {
		try {
			DatabaseEntry theKey = getKey(key);
			DatabaseEntry theData = new DatabaseEntry();
			database.get(null, theKey, theData, LockMode.DEFAULT);
			if (theData.getSize() > 0) {
				return dataBinding.entryToObject(theData);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
		return null;
	}

	private DatabaseEntry getKey(Object key)
			throws UnsupportedEncodingException {
		DatabaseEntry theKey;
		if(key instanceof String)
			theKey = new DatabaseEntry(((String)key).getBytes("UTF-8"));
		else {
			theKey = new DatabaseEntry();
			dataBinding.objectToEntry(key, theKey);
		}
		return theKey;
	}

	public boolean put(Object key, Object obj) {
		try {
			DatabaseEntry theKey = getKey(key);
			DatabaseEntry theData = new DatabaseEntry();
			dataBinding.objectToEntry(obj, theData);
			OperationStatus status = database.put(null, theKey, theData);
			return isSuccess(status);
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return false;
	}

	public boolean delete(Object key) {
		try {
			DatabaseEntry theKey = getKey(key);
			OperationStatus status = database.delete(null, theKey);
			return isSuccess(status);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
		return false;
	}

	private boolean isSuccess(OperationStatus status) {
		if(status.equals(OperationStatus.SUCCESS))
			return true;
		return false;
	}
	
	public boolean update(Object key, Object obj) {
		Object obldObject = get(key);
		if(obldObject != null) {
			if(delete(key))
				return put(key, obj);
		}
		return false;
	}

}
